﻿using System;
using System.Net.NetworkInformation;

namespace Common
{
    public static class GuardManager
    {
        private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        public static bool HasMacAddress(string mac)
        {
            bool has = false;
            NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces();
            if (nics == null || nics.Length < 1)
            {
                log.Info("No interfaces found");
                return false;
            }
            else
            {
                foreach (NetworkInterface adapter in nics)
                {
                    PhysicalAddress address = adapter.GetPhysicalAddress();
                    if (mac == address.ToString())
                    {
                        has = true;
                        break;
                    }
                }
            }
            log.Info(string.Format("Has mac address {0}? {1}", mac, has));
            return has;
        }

        public static string GetMacAddress()
        {
            string mac = string.Empty;

            NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces();
            if (nics == null || nics.Length < 1)
            {
                // If no interfaces, set default - whatever hex string you like
                mac = "6CF0490FC2F6";
                log.Info("No interfaces found, using default value.");
            }
            else
            {
                foreach (NetworkInterface adapter in nics)
                {
                    // Avoid Loopback and other adapter types	 
                    if ((adapter.NetworkInterfaceType == NetworkInterfaceType.Ethernet))
                    {
                        PhysicalAddress address = adapter.GetPhysicalAddress();
                        mac = address.ToString();
                    }
                    if (mac.Length > 0)
                    {
                        log.Info("eth : " + mac);
                        break;
                    }
                }

                if (mac == string.Empty)
                {
                    foreach (NetworkInterface adapter in nics)
                    {
                        // Avoid Loopback and other adapter types	 
                        if ((adapter.NetworkInterfaceType == NetworkInterfaceType.Wireless80211))
                        {
                            PhysicalAddress address = adapter.GetPhysicalAddress();
                            mac = address.ToString();
                        }
                        if (mac.Length > 0)
                        {
                            log.Info("WiFi : " + mac);
                            break;
                        }
                    }
                }

            }
            // In case we get no valid adapter (unlikely), then
            if (mac.Length == 0) mac = "6CF0490FC2F6";

            log.Info(string.Format("Selected MAC address {0}", mac));

            return mac;
        }

        public static long GetSerialNumber()
        {
            return GetSerialNumber(GetMacAddress());
        }

        public static long GetSerialNumber(string mac)
        {
            // This is a simple function that we use to get a serial out
            // of our MAC address. Say that x is the MAC and y is the serial,
            // the function would be y += x[i] + (i * 2) where i is the index
            // of MAC address element.
            long serial = 0;
            int index = 1;
            foreach (char c in mac)
            {
                if (char.IsDigit(c))
                {
                    serial += serial + int.Parse(c.ToString()) * (index * 2);
                }
                else if (char.IsLetter(c))
                {
                    switch (c.ToString().ToUpper())
                    {
                        case "A":
                            serial += serial + 10 * (index * 2);
                            break;
                        case "B":
                            serial += serial + 11 * (index * 2);
                            break;
                        case "C":
                            serial += serial + 12 * (index * 2);
                            break;
                        case "D":
                            serial += serial + 13 * (index * 2);
                            break;
                        case "E":
                            serial += serial + 14 * (index * 2);
                            break;
                        case "F":
                            serial += serial + 15 * (index * 2);
                            break;
                    }
                }
            }

            index++;

            log.Info(string.Format("Generated serial number {0}", serial));

            return serial;
        }

        public static long GenerateActivationCode(long serial)
        {
            long activationCode = serial * serial + 53 / serial + 113 * (serial / 4);

            if (log.IsDebugEnabled)
            {
                string code = activationCode.ToString();
                string formatted = string.Format("{0}{1}{2}", code.Substring(0, 1), new String('*', code.Length - 2), code.Substring(code.Length - 1, 1));
                log.Debug(string.Format("Generated activation code {0}", formatted));
            }

            return activationCode;
        }

        public static bool IsValid(string mac, long serialNumber, long activationCode)
        {
            log.Info(string.Format("MAC : {0}; Serial Number : {1}; Activation Code : {2}", mac, serialNumber, activationCode));

            if (HasMacAddress(mac))
            {
                long correctSerialNumber = GetSerialNumber(mac);
                long correctActivationCode = GenerateActivationCode(correctSerialNumber);

                bool isValid = serialNumber == correctSerialNumber && correctActivationCode == activationCode;

                if (isValid) log.Info("VALID");
                else log.Info("NOT VALID");

                return isValid;
            }
            else
            {
                log.Info("NOT VALID");
                return false;
            }
        }
    }
}
